use std::collections::HashMap;

use axum::{
    extract::{Query, State},
    response::IntoResponse,
    Json,
};

use crate::app_state::state::SharedState;
use crate::types::{
    blog::*,
    channel::{Request, Response},
};
use crate::utils::response::*;

use super::utils::send_to_iblog_grpc_client_and_wait;

pub async fn add(
    State(state): State<SharedState>,
    Json(blog): Json<AddRequest>,
) -> impl IntoResponse {
    dbg!("Blog add: {}", &blog);

    match send_to_iblog_grpc_client_and_wait(state.clone(), Request::BlogAdd(blog)).await {
        Ok(rsp) => {
            match rsp {
                Response::BlogAdd(id) => ok_with_message_data("新增博客成功", id),
                Response::Error(err) => error_with_message(&err),
                _ => panic!("Wrong blog add response type"),
            }
        }
        Err(err) => error_with_message(&err),
    }
}

pub async fn get(
    State(state): State<SharedState>,
    params: Query<HashMap<String, u32>>,
) -> impl IntoResponse {
    let id = *params.get("id").unwrap();
    dbg!("Getting blog: {}", id);

    match send_to_iblog_grpc_client_and_wait(state.clone(), Request::BlogGet(id)).await {
        Ok(rsp) => {
            match rsp {
                Response::BlogGet(blog) => ok_with_data(blog),
                _ => panic!("Wrong blog get response type"),
            }
        }
        Err(err) => error_with_message(&err),
    }
}

pub async fn get_multiple(
    State(state): State<SharedState>,
    params: Query<HashMap<String, u32>>,
) -> impl IntoResponse {
    let id = *params.get("id").unwrap();
    let count = *params.get("count").unwrap();

    dbg!("Getting blogs: {}/{}", id, count);

    match send_to_iblog_grpc_client_and_wait(
        state.clone(),
        Request::BlogsGet(GetMutipleRequest { id, count }),
    )
    .await
    {
        Ok(rsp) => {
            if let Response::BlogsGet(blogs) = rsp {
                ok_with_data(blogs)
            } else {
                panic!("Wrong blogs get response type");
            }
        }
        Err(err) => error_with_message(&err),
    }
}

pub async fn update(
    State(state): State<SharedState>,
    Json(blog): Json<UpdateRequest>,
) -> impl IntoResponse {
    dbg!("Updating blog: {}", &blog);

    match send_to_iblog_grpc_client_and_wait(state.clone(), Request::BlogUpdate(blog)).await {
        Ok(_) => ok(),
        Err(err) => error_with_message(&err),
    }
}

pub async fn delete(
    State(state): State<SharedState>,
    params: Query<HashMap<String, u32>>,
) -> impl IntoResponse {
    let id = *params.get("id").unwrap();
    dbg!("Deleting blog: {}", id);

    match send_to_iblog_grpc_client_and_wait(state.clone(), Request::BlogDelete(id)).await {
        Ok(_) => ok(),
        Err(err) => error_with_message(&err),
    }
}

pub async fn view_inc(
    State(state): State<SharedState>,
    params: Query<HashMap<String, u32>>,
) -> impl IntoResponse {
    let id = *params.get("id").unwrap();
    dbg!("Blog view inc: {}", id);

    match send_to_iblog_grpc_client_and_wait(state.clone(), Request::BlogViewInc(id)).await {
        Ok(rsp) => {
            if let Response::Views(views) = rsp {
                ok_with_data(views)
            } else {
                panic!("Wrong blog view inc type");
            }
        }
        Err(err) => error_with_message(&err),
    }
}

pub async fn star_inc(
    State(state): State<SharedState>,
    params: Query<HashMap<String, u32>>,
) -> impl IntoResponse {
    let id = *params.get("id").unwrap();
    dbg!("Blog view inc: {}", id);

    match send_to_iblog_grpc_client_and_wait(state.clone(), Request::BlogStarInc(id)).await {
        Ok(rsp) => {
            if let Response::Views(stars) = rsp {
                ok_with_data(stars)
            } else {
                panic!("Wrong blog stac inc response type");
            }
        }
        Err(err) => error_with_message(&err),
    }
}

pub async fn star_dec(
    State(state): State<SharedState>,
    params: Query<HashMap<String, u32>>,
) -> impl IntoResponse {
    let id = *params.get("id").unwrap();
    dbg!("Blog view inc: {}", id);

    match send_to_iblog_grpc_client_and_wait(state.clone(), Request::BlogStarDec(id)).await {
        Ok(rsp) => {
            if let Response::Views(stars) = rsp {
                ok_with_data(stars)
            } else {
                panic!("Wrong blog stac dec response type");
            }
        }
        Err(err) => error_with_message(&err),
    }
}
